package mmc.objects;

import static org.lwjgl.opengl.GL11.*;

import java.util.Map;
import org.lwjgl.opengl.GL11;

import mmc.Client;
import mmc.Constants;
import mmc.EngineObject;
import mmc.MovableEngineObject;
import mmc.Settings;
import mmc.action.skill.Skill;
import mmc.physics.PhysicsType;
import mmc.physics.Position;
import mmc.resource.Texture;
import mmc.resource.TextureLoader;
import mmc.server.Player;
import mmc.server.Server;

@SuppressWarnings("serial")
public class Mob extends MovableEngineObject {
	private static Texture tex;
	private static Texture head;
	//private transient EngineObject target;
	public int target=-1;
	
	
	private transient EngineObject spawnPoint;
	//private transient float startX, startY, startZ;
	private transient boolean back=false;
	private float rotation=0;
	private transient float swingTimer = 1;
	public boolean dead = false;
	public transient final static float SIZE = 1.6f;
	public transient final static float THICKNES = 0.33f;
	public transient final static float RUN_SPEED = 3f;
	public transient int cellCollissionsPerUpdate = 0;
	public transient float walkx=0, walkz=0;
	private float respawnTimer = 15;
	private transient double timer;
	
	static{
		if(!Constants.IS_SERVER){
			tex = TextureLoader.load("mmc/resource/data/braun.png");
			head = TextureLoader.load("mmc/resource/data/gold.png");
		}
	}

	public Mob(float x, float y, float z) {
		super(x, y, z);
		spawnPoint = new Mark(x,y,z);
		physicsType = PhysicsType.MANAGED;
	}

	
	@Override
	public void render(EngineObject observer) {		
	
		glPushMatrix();
						
        GL11.glTranslatef(x, y+0.001f, z);  
        
        
        if(Client.client.getScene().player.target != null && (this.id == Client.client.getScene().player.target.id)){			//draw circle on target
        	radialGradientCircle(new float[]{1,1,1,1}, new float[]{0,0,0,1}, 15, 0.5f);
        	
        	/*glColor3f(1, 1, 0);
        	GL11.glBegin(GL11.GL_QUADS);
        	GL11.glVertex3f(-0.5f, 0, -0.5f);
        	GL11.glVertex3f(-0.5f, 0, 0.5f);
        	GL11.glVertex3f(0.5f, 0, 0.5f);
        	GL11.glVertex3f(0.5f, 0, -0.5f);        	
        	GL11.glEnd();*/
		}
        
        
        
        GL11.glRotatef(rotation, 0.0f, 1.0f, 0.0f);        
        if(dead)
        	GL11.glRotatef(90,  0.0f, 0.0f, 1.0f);
        
        
        
        tex.bind();
        GL11.glTranslatef(0f, 0.6f, 0f);
        GL11.glScalef(0.4f, 0.4f, 0.75f);
        drawBox();				//Breast
        
        GL11.glScalef(0.2f, 1f, 0.2f);
        GL11.glTranslatef(-1f, -1f, -1.5f);
        drawBox();				//Legs
        
        GL11.glTranslatef(2f, 0f, 0f);
        drawBox();	
        
        GL11.glTranslatef(0f, 0f, 3f);
        drawBox();	
        
        GL11.glTranslatef(-2f, 0f, 0f);
        drawBox();	
        
        head.bind();
        GL11.glTranslatef(1f, 1.7f, 1f);
        GL11.glScalef(2f, 0.5f, 1f);
        drawBox();	
        
        
        /*GL11.glTranslatef(-0.5f, -1f, 0f);
        GL11.glScalef(0.2f, 1f, 0.2f);        
        drawBox();        		//Right leg
        
        GL11.glTranslatef(5f, 0f, 0f);
        drawBox();            	//Left leg
                       
        GL11.glTranslatef(3.5f, 1f, 0f);
        drawBox();				//Left arm
        
        GL11.glTranslatef(-12f, 0f, 0f);   
        drawBox();				//Right arm
        
        head.bind();        
        GL11.glTranslatef(0, 2f, 0);
        GL11.glScalef(0.1f, 0.1f, 0.1f);
        drawBox();				//Head
*/        
        
        
        
      
        glPopMatrix();
	}
	
	public void drawBox(){
		GL11.glBegin(GL11.GL_QUADS); // Start Drawing Quads
		// Front Face
		GL11.glNormal3f(0.0f, 0.0f, 0.5f); // Normal Pointing Towards Viewer
		glTexCoord2f(0, 0);
		GL11.glVertex3f(-0.5f, -0.5f, 0.5f); // Point 1 (Front)
		glTexCoord2f(1, 0);
		GL11.glVertex3f(0.5f, -0.5f, 0.5f); // Point 2 (Front)
		glTexCoord2f(1, 1);
		GL11.glVertex3f(0.5f, 0.5f, 0.5f); // Point 3 (Front)
		glTexCoord2f(0, 1);
		GL11.glVertex3f(-0.5f, 0.5f, 0.5f); // Point 4 (Front)
		// Back Face
		GL11.glNormal3f(0.0f, 0.0f, -0.5f); // Normal Pointing Away From Viewer
		glTexCoord2f(0, 0);
		GL11.glVertex3f(-0.5f, -0.5f, -0.5f); // Point 1 (Back)
		glTexCoord2f(1, 0);
		GL11.glVertex3f(-0.5f, 0.5f, -0.5f); // Point 2 (Back)
		glTexCoord2f(1, 1);
		GL11.glVertex3f(0.5f, 0.5f, -0.5f); // Point 3 (Back)
		glTexCoord2f(0, 1);
		GL11.glVertex3f(0.5f, -0.5f, -0.5f); // Point 4 (Back)
		// Top Face
		GL11.glNormal3f(0.0f, 0.5f, 0.0f); // Normal Pointing Up
		glTexCoord2f(0, 0);
		GL11.glVertex3f(-0.5f, 0.5f, -0.5f); // Point 1 (Top)
		glTexCoord2f(1, 0);
		GL11.glVertex3f(-0.5f, 0.5f, 0.5f); // Point 2 (Top)
		glTexCoord2f(1, 1);
		GL11.glVertex3f(0.5f, 0.5f, 0.5f); // Point 3 (Top)
		glTexCoord2f(0, 1);
		GL11.glVertex3f(0.5f, 0.5f, -0.5f); // Point 4 (Top)
		// Bottom Face
		GL11.glNormal3f(0.0f, -0.5f, 0.0f); // Normal Pointing Down
		glTexCoord2f(0, 0);
		GL11.glVertex3f(-0.5f, -0.5f, -0.5f); // Point 1 (Bottom)
		glTexCoord2f(1, 0);
		GL11.glVertex3f(0.5f, -0.5f, -0.5f); // Point 2 (Bottom)
		glTexCoord2f(1, 1);
		GL11.glVertex3f(0.5f, -0.5f, 0.5f); // Point 3 (Bottom)
		glTexCoord2f(0, 1);
		GL11.glVertex3f(-0.5f, -0.5f, 0.5f); // Point 4 (Bottom)
		// Right face
		GL11.glNormal3f(0.5f, 0.0f, 0.0f); // Normal Pointing Right
		glTexCoord2f(0, 0);
		GL11.glVertex3f(0.5f, -0.5f, -0.5f); // Point 1 (Right)
		glTexCoord2f(1, 0);
		GL11.glVertex3f(0.5f, 0.5f, -0.5f); // Point 2 (Right)
		glTexCoord2f(1, 1);
		GL11.glVertex3f(0.5f, 0.5f, 0.5f); // Point 3 (Right)
		glTexCoord2f(0, 1);
		GL11.glVertex3f(0.5f, -0.5f, 0.5f); // Point 4 (Right)
		// Left Face
		GL11.glNormal3f(-0.5f, 0.0f, 0.0f); // Normal Pointing Left
		glTexCoord2f(0, 0);
		GL11.glVertex3f(-0.5f, -0.5f, -0.5f); // Point 1 (Left)
		glTexCoord2f(1, 0);
		GL11.glVertex3f(-0.5f, -0.5f, 0.5f); // Point 2 (Left)
		glTexCoord2f(1, 1);
		GL11.glVertex3f(-0.5f, 0.5f, 0.5f); // Point 3 (Left)
		glTexCoord2f(0, 1);
		GL11.glVertex3f(-0.5f, 0.5f, -0.5f); // Point 4 (Left)
		GL11.glEnd(); // Done Drawing Quads
	}
	
	public void drawBox2(){
	       GL11.glBegin(GL11.GL_QUADS);				
	        
	       GL11.glNormal3f( 0.0f, 0.0f, 1.0f);
	        glTexCoord2f(0, 0);
	    	GL11.glVertex3f(-0.25f, 0.5f, 0.25f);            
	    	glTexCoord2f(1, 0);
	    	GL11.glVertex3f( -0.25f, 1.0f, 0.25f);
	       	glTexCoord2f(0, 1);
	    	GL11.glVertex3f( 0.25f, 1.0f, 0.25f);       	
	    	glTexCoord2f(1, 1);
	    	GL11.glVertex3f( 0.25f, 0.5f, 0.25f);
	    
	    GL11.glNormal3f( 0.0f, 0.0f, -1.0f);
	        glTexCoord2f(0, 0);
	    	GL11.glVertex3f(-0.25f, 0.5f, -0.25f);            
	    	glTexCoord2f(1, 0);
	    	GL11.glVertex3f( -0.25f, 1.0f, -0.25f);
	       	glTexCoord2f(0, 1);
	    	GL11.glVertex3f( 0.25f, 1.0f, -0.25f);       	
	    	glTexCoord2f(1, 1);
	    	GL11.glVertex3f( 0.25f, 0.5f, -0.25f);
	    
	    	 GL11.glNormal3f( 0.0f, -1.0f, 0.0f);
	        glTexCoord2f(0, 0);
	    	GL11.glVertex3f(-0.25f, 0.5f, -0.25f);            
	    	glTexCoord2f(1, 0);
	    	GL11.glVertex3f( -0.25f, 0.5f, 0.25f);
	       	glTexCoord2f(0, 1);
	    	GL11.glVertex3f( 0.25f, 0.5f, 0.25f);       	
	    	glTexCoord2f(1, 1);
	    	GL11.glVertex3f( 0.25f, 0.5f, -0.25f);
	    	
	    	 GL11.glNormal3f( 0.0f, 1.0f, 0.0f);
	        glTexCoord2f(0, 0);
	    	GL11.glVertex3f(-0.25f, 1f, -0.25f);            
	    	glTexCoord2f(1, 0);
	    	GL11.glVertex3f( -0.25f, 1f, 0.25f);
	       	glTexCoord2f(0, 1);
	    	GL11.glVertex3f( 0.25f, 1f, 0.25f);       	
	    	glTexCoord2f(1, 1);
	    	GL11.glVertex3f( 0.25f, 1f, -0.25f);

	    	 GL11.glNormal3f( 1.0f, 0.0f, 0.0f);
	        glTexCoord2f(0, 0);
	    	GL11.glVertex3f(-0.25f, 0.5f, -0.25f);            
	    	glTexCoord2f(1, 0);
	    	GL11.glVertex3f( -0.25f, 1f, -0.25f);
	       	glTexCoord2f(0, 1);
	    	GL11.glVertex3f( -0.25f, 1f, 0.25f);       	
	    	glTexCoord2f(1, 1);
	    	GL11.glVertex3f( -0.25f, 0.5f, 0.25f);
	    	
	    	 GL11.glNormal3f( -1.0f, 0.0f, 0.0f);
	        glTexCoord2f(0, 0);
	    	GL11.glVertex3f(0.25f, 0.5f, -0.25f);            
	    	glTexCoord2f(1, 0);
	    	GL11.glVertex3f( 0.25f, 1f, -0.25f);
	       	glTexCoord2f(0, 1);
	    	GL11.glVertex3f( 0.25f, 1f, 0.25f);       	
	    	glTexCoord2f(1, 1);
	    	GL11.glVertex3f( 0.25f, 0.5f, 0.25f);    	       
	        GL11.glEnd();
	}

	@Override
	public void update(float dt) {
		if(vy*vy>0.1)
			vy += Settings.PHYSICS_GRAVITY*dt;
		
		x += vx*dt;
		y += vy*dt;
		z += vz*dt;
		
	}
	
	private void applyRunSpeed(float speed){
		if(walkx!=0||walkz!=0){
			
			float v2 = vx*vx+vz*vz;
			
			if(v2 > speed*speed*1.1f){ //way too fast
				return;
			}
			
			
			float a = speed/(float) Math.sqrt(walkx*walkx+walkz*walkz);
			walkx *= a;
			walkz *= a;
			
			vx = walkx;
			vz = walkz;
		}
	}
	
	@Override
	public void update(Server server, float dt) {

		//System.out.println(stats.getPercentalValue(StandardStats.HP));
		if(dead){				//respawn
			timer -= dt;
			if(timer<0){
				dead = false;
				health = 1.0f;
				vy += 20;
			}
				
			return;
		}
		
		if(!inFlatRange(spawnPoint, 20) || (target!=-1 && targetInactiv(server))){		//Go back to spawn point if target disconnects or mob to far away from spawn
			back = true;
		}
		
		if(back){
			target = -1;
			goTo(spawnPoint);	
			if(inFlatRange(spawnPoint, 1))
				back = false;
		}else{
			if(target == -1)
			{
				Map<Integer, EngineObject> map = server.getScene().objects;
				
				for(Map.Entry<Integer, EngineObject> entry : map.entrySet())
				{
					if(entry.getValue() instanceof Player)
						if(inRange(entry.getValue(), 10))
							target = entry.getKey();
				}
				
				randomWalk(dt);
			}
			else{
				if(inRange(server.getScene().objects.get(target), 1)){
					attack(server, dt);
				}else{
					goTo(server.getScene().objects.get(target));
				}
			}
		}
		
		applyRunSpeed(RUN_SPEED);
		cellCollissionsPerUpdate = 0;
		dirty = true;
	}
	
	public void randomWalk(float dt)
	{
		rotation = (rotation+(float)(Math.random()-0.5)*180*dt)%360;
		
		walkx = (float) Math.sin(rotation*Math.PI/180);
		walkz = (float) Math.cos(rotation*Math.PI/180);
		
		if(cellCollissionsPerUpdate>1)
			if(vy==0){//jump
				vy += 20;
			}
	}
	
	public boolean targetInactiv(Server server){
		return !server.getScene().objects.containsKey(target);
	}
	
	public void attack(Server server, float dt)
	{
		walkx=walkz=0;
		if(swingTimer > 0)
			swingTimer -= dt;
		else
		{
			server.getScene().objects.get(target).takeDamage(Skill.randomDMG(2, 15));
			swingTimer = 1;
		}
	}
	
	@Override
	public void notifyCellCollission(Position pos) {
		cellCollissionsPerUpdate++;
	}

	private void goTo(EngineObject target){
		walkx = target.x - this.x;
		walkz = target.z - this.z;
		rotation = (float) ((float) Math.atan2(walkx, walkz)*180/Math.PI);
		
		if(cellCollissionsPerUpdate>1)
			if(vy==0){//jump
				vy += 20;
			}
	}
	
	public boolean inFlatRange(EngineObject other, float range){
		float dx = x-other.x,
			  dz = z-other.z;
		
		return dx*dx+dz*dz < range*range; 
	}
	
	@Override
	public void kill(){
		dead = true;
		timer = respawnTimer;
		target = -1;
		walkx=walkz=0;
		dirty = true;
	}

}

